import socket
import struct
import select
import time
import os
from decimal import Decimal
import kmeans

'''
typedef struct _icmphdr{
unsigned char i_type; 
unsigned char i_code; 
unsigned short i_cksum; 
unsigned short i_id ; 
unsigned short i_seq ; 
unsigned int timestamp; // ??? diff from wireshark
}ICMP_HEADER; 

struct.pack()
select
'''

timeout = 10
ICMP_ECHO_REQUEST = 8
PID = os.getpid()
 

def sendpkt(sock,dstip,pktsize,seqno): 
    pkt = generatepkt(pktsize,seqno)
    dst  = socket.gethostbyname(dstip)
    sock.sendto(pkt, (dst, 1))

def recvpkt(sock):
    time_remaining = timeout
    result  = []
    while True:
        start_time = time.time()
        readable = select.select([sock], [], [], time_remaining)
	#print ("****readable is **",readable)
        time_spent = time.time() - start_time
        if readable[0] == []:
            return result 
            #return
     
        time_received = time.time()
        recv_packet, addr = sock.recvfrom(2048)
	#print "receive data",recv_packet,addr
        #print "rec len",len(recv_packet)
        icmp_header = recv_packet[20:28]
        type, code, checksum, packet_ID, sequence = struct.unpack(
            "bbHHh", icmp_header
        )
	#print type, code, checksum, packet_ID, sequence
        time_remaining = time_remaining - time_spent
        if time_remaining <= 0:
            print "fail"
            return 
        if packet_ID == PID:
            bytes_In_double = struct.calcsize("d")
            time_sent = struct.unpack("d", recv_packet[28:28 + bytes_In_double])[0]
            delay = (time_received-time_sent)*1000
            #print delay
            result.insert(sequence-1, delay)
            if len(result) == 3:
                return result

    return result    


def generatepkt(pktsize,seqno):
    i_id = PID#os.getpid()

    header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, 0, i_id, seqno)
    bytes_In_double = struct.calcsize("d")
    data = (192 - bytes_In_double) * "Q"
    data = struct.pack("d", time.time()) + data
    data = data + "d"*pktsize

    my_checksum = do_checksum(header + data)
    header = struct.pack(
        "bbHHh", ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), i_id, seqno
    )
    packet = header + data
    return packet


def do_checksum(source_string):
    sum = 0
    max_count = (len(source_string)/2)*2
    count = 0
    while count < max_count:
        val = ord(source_string[count + 1])*256 + ord(source_string[count])
        sum = sum + val
        sum = sum & 0xffffffff 
        count = count + 2

    if max_count<len(source_string):
        sum = sum + ord(source_string[len(source_string) - 1])
        sum = sum & 0xffffffff
    sum = (sum >> 16)  +  (sum & 0xffff)
    sum = sum + (sum >> 16)
    answer = ~sum
    answer = answer & 0xffff
    answer = answer >> 8 | (answer << 8 & 0xff00)
    return answer

def run(hx,hy,count = 3):
    #print "----------------------run sandwich------------------\n"
    add = 0
    for i  in range(count):
        sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname("icmp"))
        #recvpkt(sock)
        sendpkt(sock, hx, 5000, 1)
        sendpkt(sock, hy, 50000,2)
        sendpkt(sock, hx, 5000,3)
        sandwichdelay = recvpkt(sock)
        #print sandwichdelay

        if len(sandwichdelay) != 3:
            print "fail"
        else:
            diff  = abs(sandwichdelay[0] - sandwichdelay[2])
        add = add + diff
    aver = add/count 
    return aver

def div(l):
    #print "----------------------div------------------\n"
    '''
    cluster = kmeans.run('/home/zxg/scandir/1M0.1ms.txt',2)
    layer = []
    tmpl = []
    val = cluster[:,0][0]
    for i in range(cluster.shape[0]):
        if cluster[:,0][i] == val:
        	tmpl.append(int(i)+2)
        	#print tmpl
        else:
        	layer.append(tmpl)
        	tmpl = []
        	tmpl.append(int(i)+2)
        	val = cluster[:,0][i]
    layer.append(tmpl)
    print layer
    '''
    lhx = []
    lhy = []
    diffxy = []
    #for l in layer:
    for i in range(len(l)):
        for j in range(i+1,len(l)):
            hx = "10.0.0."+ str(l[i])
            hy = "10.0.0."  + str(l[j])
            diff = round(run(hx,hy,3))
            #print l[i],l[j],diff
            #print diff
            lhx.append(l[i])
            lhy.append(l[j])
            diffxy.append(diff)

    return lhx,lhy,diffxy

def con(l1, l2):
    #print "----------------------con------------------\n"
    lhx = []
    lhy = []
    diffxy = []
    i = 0
    j = 0
    for lx in l1:
        i = i + 1
        j =  0
        for ly in l2:
            j = j + 1
            hx = "10.0.0." + str(lx[0])
            hy = "10.0.0." + str(ly[0])
            diff = round(run(hx,hy,3))
            lhx.append(i)
            lhy.append(j)
            diffxy.append(diff)
    
    return lhx,lhy,diffxy

if __name__ =="__main__":
     #div([2,3,7,8,5,6])
     #con()
     run("10.0.0.2","10.0.0.7",3)
